/*filename: pps.c*/

#include <sys/types.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <strings.h>
#include <string.h>
#include <iostream>
#include <syslog.h>
#include <signal.h>
#include <sys/stat.h>

#include "utils.h"
#include "libcli.h"
#include "pps.h"
#include "ppscommand.h"
#include "ppsadapter.h"
#include "checklicense.h"
#include "send_http_msg.h"
#include "version.h"
#include "dmacard.h"
#include "worker.h"

void InitUdpSocket();

time_t g_tm;
char g_log_dir_name[PPS_PATH_MAX];

int main(int argc,char * argv[])
{
	int arg,bg=0,ret = 0;
	int hashFlag=0, hashType = 0;
	char hashUrl[2048] = {0};
	extern int optopt;
	extern char *optarg;

	if(argc<2){
		printf("usage:ppsd -d workdir -h hashsize \n");
		return 0;
	}

	set_conf_dir("./");
	while ((arg = getopt(argc, argv, "mvbh:d: ")) != EOF) {
		switch (arg) {
		case 'v':
			printf("%s\n",verno);
			return 0;
		case 'd':
			set_conf_dir(optarg);
			break;
		case 'b':
			bg=1;
			break;

		case 'm':
			printf("Version: %s\n", verno);
			printf("Update: \n%s\n", _UPDATEINFO);
			return 0;
        //case 'h':
        //    worker_hashsize = atoi(optarg);
        //    break;
		default:
			printf("error: unrecognized switch '%c'", optopt);
			break;
		}
	}

#if 0
	/*check license*/
	while(1){
		if(0 ==check_license (get_conf_dir(),"pps",&g_tm))
		{
			break;
		}
		syslog(LOG_ERR,"license error!");	
		sleep(60);
	}

	if( (g_tm != 0) && (g_tm < time(0)))
	{
		syslog(LOG_ERR,"license has expired!");   
		exit(0);
	}
	syslog(LOG_ERR,"check license successfully!");	 
#endif

	if(bg==1){
		/*daemon initiation*/
		daemon_init();
	}
	/*check if the pps run only one copy.*/
	ret = check_only_one_process(PPS_PID_FILE_NAME);
	if (ret != 0){
		printf("only a copy of system is permitted. exit!\n");
		exit(EXIT_SUCCESS);
	}
	/*Initialize PPS*/ 
	InitPPS();
        InitUdpSocket();

	int perr;
#ifdef PPS_32
        switch(gbl_get_network_card_type()){
        case 0:
                init_dmacard();
                break;
        case 1:
				init_dmacard_10G();
                break;
        default:
                printf("network card configure error!\n");
                exit(EXIT_FAILURE);
        }
#endif

        /*create packet receive threads */
#ifndef PPS_32
        perr = start_packet_pthread(); 
#else
        if(gbl_get_network_card_type()==0)
        {
            perr = start_packet_pthread();
        }
        else
        {
            perr = start_packet_pthread_10G();
        }
#endif
        if (perr != 0) {
                printf("fail to create thread of packet handler.(%s)\n", strerror(errno));
                pps_dbg_print(0,PROTOCOL_GLOBE, "fail to create thread of packet handler.(%s)\n", strerror(errno));
                exit(EXIT_FAILURE);
        }

	/*handle commands from super managers*/
	struct cli_def *cli = cli_init();

	ConfigCli(cli);

	int socketCli;
	socketCli = socket(AF_INET, SOCK_STREAM, 0);

	if (socketCli < 0 ) {
		printf("fail to create socket for cli interface.(%s)\n", strerror(errno));
		pps_dbg_print(0,PROTOCOL_GLOBE, "fail to create socket for cli interface.(%s)\n", strerror(errno));
		exit(EXIT_FAILURE);
	}

	int on = 1;
	setsockopt(socketCli, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));

	//get cli server port from config file
	u_short cliport = cfg_read_cli_port();
	if(cliport <= 0)
		cliport = PPS_CLI_PORT;

	struct sockaddr_in svrAddr;
	bzero(&svrAddr, sizeof(svrAddr));
	svrAddr.sin_family = AF_INET;
	svrAddr.sin_addr.s_addr = htonl(INADDR_ANY);

	u_short retry = 0;
	do{
		svrAddr.sin_port = htons(cliport);
		ret = bind(socketCli, (struct sockaddr*)&svrAddr, sizeof(svrAddr));
		if(ret == 0)
			break;
		cliport++;
	}while(retry < PPS_BIND_RETRY);

	if(ret < 0){
		printf("fail to bind socket for cli interface.(%s)\n", strerror(errno));
		pps_dbg_print(0,PROTOCOL_GLOBE, "fail to bind socket for cli interface.(%s)\n", strerror(errno));
		exit(EXIT_FAILURE);
	}

	if ( listen(socketCli, 1) < 0 ) {
		printf("fail to listen on cli socket.(%s)\n", strerror(errno));
		pps_dbg_print(0,PROTOCOL_GLOBE, "fail to listen on cli socket.(%s)\n", strerror(errno));
		exit(EXIT_FAILURE);
	}

	pps_dbg_print(0,PROTOCOL_GLOBE, "%s now run...","ppsd");

	int socketTemp;
	while ( (socketTemp = accept(socketCli, NULL, 0)) ) {
		cli_loop(cli, socketTemp);
		close(socketTemp);
	}

	cli_done(cli);

	close(socketCli);
	syslog(LOG_USER|LOG_ERR, "system Normal exit.\n");



    
	return 0;
}

/***************************************************************************************/
void InitPPS()
{
	int ret = 0;

    worker_global_init();
    
	/*open system log*/
	openlog("ppsd", LOG_PID, LOG_USER);

	/*Initialize the log */
	ret = create_log_dir();
	if (ret != 0){
		pps_dbg_print(0,PROTOCOL_GLOBE,"fail to create directory that contains logs. (%s)\n", strerror(errno));
		exit(EXIT_FAILURE);
	}

	char run_log_name[PPS_PATH_MAX];
	sprintf(run_log_name, "%s/%s", g_log_dir_name, PPS_RUN_LOG_FILE_NAME);

	pps_dbg_print(0,PROTOCOL_GLOBE, "verno:%s.",verno);
	/*initialize pps's system data.*/
	gbl_init();

	//2. configurate the id of pps
	ret = cfg_read_id();
	if (ret < 0){
		pps_dbg_print(0,PROTOCOL_GLOBE,"can't find id in config file.\n");
		exit(EXIT_FAILURE);
	}

	//4. configurate the debug level
	ret = cfg_read_debug_level();
	if (ret < 0){
		pps_dbg_print(0,PROTOCOL_GLOBE,"debuglevel scope:0-%d.\n",DEBUG_LEVEL_MAX);
		exit(EXIT_FAILURE);
	}

	//10. configurate the network card type,default is GB
	cfg_read_network_card_type();

	//11. configurate the dma of pps
	ret = cfg_read_DMA();
	if (ret <= 0){
		pps_dbg_print(0,PROTOCOL_GLOBE,"can't find DMA card in config file.\n");
		exit(EXIT_FAILURE);
	}else    
	{
		if(gbl_get_network_card_type()==0){
			if(ret>ZCOPY_MAXCARD){
				pps_dbg_print(0,PROTOCOL_GLOBE,"too many DMA card .\n");
				exit(EXIT_FAILURE);
			}
		}else
		{
			if(ret>ZCOPY_MAXCARD_10G){
				pps_dbg_print(0,PROTOCOL_GLOBE,"too many DMA card .\n");
				exit(EXIT_FAILURE);
			}
		}
		pps_dbg_print(0,PROTOCOL_GLOBE, "read %d DMACARD from config file.", ret);
	}

    /* add by chenyun for regular info begin */
    cfg_read_regular_debug();

    ret = cfg_read_regular_info();
	if (ret <= 0){
		pps_dbg_print(0,PROTOCOL_GLOBE,"can't find regular info in config file.\n");
		exit(EXIT_FAILURE);
	}else    
	{
        
    }

    /* add by chenyun for regular info end */

    
	//read module clientpool use on-off
	cfg_read_clientpool_redirect();
	pps_dbg_print(0,PROTOCOL_GLOBE, "read clientpool direct: %d", pps_get_clientpool_redirect());
	
	//14. configurate host range
	ret = cfg_read_ipscope();
	if (ret < 0){
		pps_dbg_print(0,PROTOCOL_GLOBE,"read ip scope fail.");
		exit(EXIT_FAILURE);
	}
	else
		pps_dbg_print(0,PROTOCOL_GLOBE, "read %d hosts from config file.", ret);
	pps_unite_add_ipscope_table(gbl_get_ipscope_tbl(), gbl_get_ipscope_all_tbl(), 1);

	pps_dbg_print(0,PROTOCOL_GLOBE, "success to initialize system.");
	return ;
}

void ExitPPS(void)
{

	gbl_destroy();
	pps_destroy_raw_sock();
	pps_dbg_print(0,PROTOCOL_GLOBE, "fail to load system.\n");

	closelog();
}

int create_log_dir()
{
	//	char cur_dir[PPS_PATH_MAX] = {0};
	int rval = 0;

	//	get_executable_path(cur_dir, PPS_PATH_MAX);

	sprintf(g_log_dir_name, "%s/%s", get_conf_dir(), PPS_LOG_DIR_NAME);

	if (access(g_log_dir_name, F_OK) != 0)//directory does not exist.
		rval = mkdir(g_log_dir_name, S_IWGRP|S_IRGRP|S_IRUSR|S_IWUSR|S_IXUSR|S_IXOTH|S_IROTH);

	return rval;
}
